package cn.csq.linked;

import java.util.LinkedList;

/**
 * @author <a href="mailto:csq02198031@alibaba-inc.com">chengshanqing</a>
 * @date 2025/8/21 11:29
 */
public class Test707 {


    public static void main(String[] args) {

//        永远不要在遍历时修改 head 或 tail，使用临时变量遍历。
//        双向链表操作需同时更新 prev 和 next，避免指针断裂。
//        索引越界检查 是必须的，防止访问 tail 或 null 节点。
        MyLinkedList myLinkedList = new MyLinkedList();
        System.out.println("linked List = " + myLinkedList.toString()); // 输出: 空
        for (int i = 0; i < 10; i++) {
            myLinkedList.addLast(i);
        }
        System.out.println("linked List = " + myLinkedList.toString()); // 输出: 0 <-> 1 <-> ... <-> 9
        myLinkedList.add(4, 100);
        System.out.println("linked List = " + myLinkedList.toString()); // 输出: 0 <-> 1 <-> 2 <-> 3 <-> 100 <-> 4 <-> ... <-> 9
    }
/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList obj = new MyLinkedList();
 * int param_1 = obj.get(index);
 * obj.addAtHead(val);
 * obj.addAtTail(val);
 * obj.addAtIndex(index,val);
 * obj.deleteAtIndex(index);
 */
}

/**
 * 你可以选择使用单链表或者双链表，设计并实现自己的链表。
 * <p>
 * 单链表中的节点应该具备两个属性：val 和 next 。val 是当前节点的值，next 是指向下一个节点的指针/引用。
 * <p>
 * 如果是双向链表，则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
 * <p>
 * 实现 MyLinkedList 类：
 * <p>
 * MyLinkedList() 初始化 MyLinkedList 对象。
 * int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效，则返回 -1 。
 * void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后，新节点会成为链表的第一个节点。
 * void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
 * void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度，那么该节点会被追加到链表的末尾。如果 index 比长度更大，该节点将 不会插入 到链表中。
 * void deleteAtIndex(int index) 如果下标有效，则删除链表中下标为 index 的节点。
 */
class MyLinkedList {
    private int size;
    private MyListNode head;
    private MyListNode tail;

    public MyLinkedList() {
        this.size = 0;
        this.head = new MyListNode(0);
        this.tail = new MyListNode(0);
        head.next = tail;
        tail.prev = head;
    }

    public int get(int index) {
        /*for (int i = 0; i <= index; i++) {
            this.head = this.head.next; // ❌ 错误：修改 head 指针！
        }
        return head.val;*/
        // 直接修改了head节点，不能去修改指针,采用临时变量的方式
        MyListNode p = head.next; // ✅ 使用临时变量 p 遍历
        for (int i = 0; i < index && p != tail; i++) {
            p = p.next;
        }
        if (p == tail) return -1; // 索引越界
        return p.val;
    }

    public void addLast(int val) {
        MyListNode x = new MyListNode(val);
        // x<-> tail 操作一个节点因为是双链表，因为涉及一个节点的两个方向，对应了四个指针，上一个节点的next、当前节点的prev、当前节点的next 、下个节点的prev
        MyListNode temp = this.tail.prev;
        // head<->x<-tail
        x.prev = temp;

        x.next = tail;
        temp.next = x;
        tail.prev = x;
        size++;


    }

    // 从头加入节点
    public void addAtHead(int val) {
        // 构建节点
        MyListNode x = new MyListNode(val);

        MyListNode temp = head.next;

        //head<->tmp
        head.next = x;
        x.prev = head;

        x.next = temp;
        temp.prev = x;
        //head<->x<->tmp

        size++;

    }

    public void add(int index, int val) {
//        MyListNode x = new MyListNode(val);
//        MyListNode p = getNode(index); // ❌ getNode 会修改 head 指针
//        MyListNode temp = p.prev;
//        temp.next = x;
//        x.prev = temp;
//        x.next = head; // ❌ 错误：此时 head 可能已被修改
//        head.prev = x;
//        size++;

        if (index < 0 || index > size) return;
        MyListNode p = head;
        for (int i = 0; i < index; i++) {
            p = p.next;
        }
        MyListNode x = new MyListNode(val);
        x.prev = p;
        x.next = p.next;
        p.next.prev = x;
        p.next = x;
        size++;

    }

    // 校验


    // 从尾巴加入节点
    public void addAtTail(int val) {

    }

    public void addAtIndex(int index, int val) {

    }

    public void deleteAtIndex(int index) {

    }

    public MyListNode getNode(int index) {
        MyListNode p = head.next;
        for (int i = 0; i < index; i++) {
            p = p.next;
        }
        return p;
    }

    private boolean checkElementIndex(int index) {
        return true;
    }

    @Override
    public String toString() {
        /*StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < size; i++) {
            head = head.next; // ❌ 错误：修改 head 指针！
            stringBuffer.append(head.val);
            if (head.next != tail) {
                stringBuffer.append(" <-> ");
            }
        }
        return new String(stringBuffer);*/

        MyListNode p = head.next; // ✅ 使用临时变量 p 遍历
        StringBuffer stringBuffer = new StringBuffer();
        while (p != tail) {
            stringBuffer.append(p.val);
            if (p.next != tail) {
                stringBuffer.append(" <-> ");
            }
            p = p.next;
        }
        return stringBuffer.toString();
    }

}

class MyListNode {
    public int val;
    public MyListNode prev;
    public MyListNode next;

    public MyListNode(int val) {
        this.val = val;
    }
}
